/**
 * @brief TI TMP112 系列温度传感器驱动
 * @detail TMP112 系列只在与 SMBus、两线制和 I2C 接口兼容的总线上作为从器件运行，并通过开漏 I/O 线路 SDA 和 SCL 与 MCU 建立连接
 * @author 张勇 / 2020-05-13
 */

#include "_mcu_gpio.h"
#include "tmp112.h"

// TMP112 的设备读写地址
#define TMP112_RADDR(dev) ((uint8_t)((dev->addr << 1) | 1))
#define TMP112_WADDR(dev) ((uint8_t) (dev->addr << 1))

// TMP112 有 4 个 16-bit 寄存器
#define TMP112_REGADDR_TEMP     0x00 ///< 温度寄存器（只读）
#define TMP112_REGADDR_CONF     0x01 ///< 配置寄存器（ 读取/写入）
#define TMP112_REGADDR_TLOW     0x02 ///< TLOW 寄存器（ 读取/写入）
#define TMP112_REGADDR_THIGH    0x00 ///< THIGH 寄存器（ 读取/写入）

// 转换读出来的温度寄存器值为整数表示的温度(单位: 0.01C)
static int32_t _temperature_convert_from_reg(uint8_t temp[2]) {    
    int16_t rawTemp = (temp[0] << 4) | (temp[1] >> 4);
    if(rawTemp > 0x7FF) {
        rawTemp |= 0xF000; // 负数，进行符号扩展
    }
    return rawTemp * 625 / 100; // 每个LSB为0.0625°C
}

// 转换读出来的温度寄存器值为整数表示的温度(单位: 0.01C)
static std_err_t _temperature_convert_to_reg(int32_t val, uint8_t temp[2]) {
    return STD_ERR_OK;
}

std_err_t unidrv_tmp112_read_temperature(unidrv_tmp112_t* dev, int32_t* temperature) {
    if(!dev || !dev->i2c || dev->addr < 0x40 || dev->addr > 0x4B || !temperature) return STD_ERR_INVALID_ARG;
    std_err_t err;
    
    // 产生start条件；写入要读的寄存器地址为 温度寄存器
    uint8_t buf1[] = {TMP112_WADDR(dev), TMP112_REGADDR_TEMP};
    err = mcu_i2c_master_trx(dev->i2c, true, false, 2, buf1, 0, NULL); if(err) return err;

    // 产生repeat-start条件；读取 2 字节 温度寄存器 值；产生stop条件
    uint8_t addr = TMP112_RADDR(dev);
    uint8_t temp[2];
    err = mcu_i2c_master_trx(dev->i2c, true, true, 1, &addr, 2, temp); if(err) return err;
    
    // 转换读出来的温度寄存器值为整数表示的温度(单位: 0.01C)
    *temperature = _temperature_convert_from_reg(temp);
    return STD_ERR_OK;
}

std_err_t unidrv_tmp112_alert_config(unidrv_tmp112_t* dev, int32_t thigh, int32_t tlow, unidrv_tmp112_alert_callback_t alert_callback, void* alert_callback_cookie) {
    if(!dev || !dev->i2c || !alert_callback) return STD_ERR_INVALID_ARG;
    std_err_t err;
    uint8_t temp[2];
    
    err = _temperature_convert_to_reg(thigh, temp); if(err) return err;
    
    return STD_ERR_NOT_SUPPORTED;
}

std_err_t unidrv_tmp112_alert_enable(unidrv_tmp112_t* dev, bool enable) {
    return STD_ERR_NOT_SUPPORTED;
}

std_err_t unidrv_simi2c_tmp112_read_temperature(unidrv_simi2c_t *dev, uint8_t addr, int *value) {
	// TMP112 读写地址
	uint8_t	TMP112_WRITE_ADDRESS = ((addr << 1) | 0);
	uint8_t	TMP112_READ_ADDRESS	 = ((addr << 1) | 1);
	// TMP112 有 4 个 16-bit 寄存器
	#define TMP112_REGADDR_TEMP     0x00 ///< 温度寄存器（只读）
	#define TMP112_REGADDR_CONF     0x01 ///< 配置寄存器（ 读取/写入）
	#define TMP112_REGADDR_TLOW     0x02 ///< TLOW 寄存器（ 读取/写入）
	#define TMP112_REGADDR_THIGH    0x00 ///< THIGH 寄存器（ 读取/写入）
	
	uint8_t temp[2];
	
	// 发送开始测量湿度的指令(保持 Master 模式)
	unidrv_simi2c_start(dev);
	if(!unidrv_simi2c_tx(dev, TMP112_WRITE_ADDRESS)) { unidrv_simi2c_stop(dev); return STD_ERR_TIMEOUT; }
	if(!unidrv_simi2c_tx(dev, TMP112_REGADDR_TEMP))  { unidrv_simi2c_stop(dev); return STD_ERR_TIMEOUT; }

	// 发送读取湿度指令，并读取湿度值
	unidrv_simi2c_start(dev);
	if(!unidrv_simi2c_tx(dev, TMP112_READ_ADDRESS))  { unidrv_simi2c_stop(dev); return STD_ERR_TIMEOUT; }
	temp[0] = unidrv_simi2c_rx(dev, true);
	temp[1] = unidrv_simi2c_rx(dev, false);
	unidrv_simi2c_stop(dev);
	 
    int16_t rawTemp = (temp[0] << 4) | (temp[1] >> 4);
    if(rawTemp > 0x7FF) {
        rawTemp |= 0xF000; // 负数，进行符号扩展
    }

	*value = rawTemp * 625 / 100; // 每个LSB为0.0625°C
	return STD_ERR_OK;
}
